/***********************************************************
 * Author: 	Brandon McKune
 * E-Mail:	bmckune.cs@gmail.com
 * Date:	September 2, 2011
 * Class:	Advanced OS
 * Time:	1150 - 1325
 * Smstr:	Fall 2011
 */
#include "ClTask.h"

#define TO_NANOSECONDS	1000000000

/**
 * 	ClTask() Default Constructor:
 * 	Description:
 * 		This method does nothing to generate the tasks
 * 		that is created.  This function initializes everything
 * 		to 0.
 * 	Parameters:
 * 		N/A
 * 	Output:
 * 		N/A
 */
ClTask::ClTask() {
	this->m_uint64ArrivalTime = 0;
	this->m_uint64DeadlineTime = 0;
	this->m_uint64ComputationalTime = 0;
	this->m_uint64NumInstructions = 0;
	this->m_uint64NumInstructionsCompleted = 0;
	this->m_uint64FinishedTime = 0;
	this->m_uint64MaxProcSpeedHz = 0;
	this->m_uint64AverageProcessedRateHz = 0;
}

/**
 * 	~ClTask() Default Destructor:
 * 	Description:
 * 		This method frees up memory of the object.  Nothing is created
 * 		dynamically, thus this function does nothing.
 * 	Parameters:
 * 		N/A
 * 	Output:
 * 		N/A
 */
ClTask::~ClTask() {
	//Do nothing, this
}

/**
 * 	randomize() Function:
 * 	Description:
 * 		The randomize function randomly chooses the number of instructions
 * 		that the task has to execute.  This function also insures that the
 * 		deadline time is not impossible to reach given the number of instructions.
 * 	Parameters:
 * 		uint64_t Hz
 * 			The default speed of the processors.  This is used to determine if
 * 			the deadline can be met.
 * 	Output:
 * 		void
 */
void ClTask::randomize(uint64_t Hz) {
	this->setArrivalTime(ClRTClock::getInstance()->getTimeInterval());
	this->setMaxProcSpeedHz(Hz);

	//Generate a set of three numbers.
	uint64_t possibleInstructions;
	double temp_compTime;
	for (int i = 0; i < 3; i++) {
		possibleInstructions += rand();
		//sleep(1);
	}

	if (possibleInstructions % 2 == 0) {
		possibleInstructions = 11 * rand() % 100000;
	}else if(possibleInstructions > INT_MAX){
		possibleInstructions = rand() % 10000;
	}else{
		possibleInstructions %= 1000000;
	}

	this->m_uint64NumInstructions = (uint32_t) possibleInstructions;

	//Find out how many seconds it will take to execute this task
	//given a max processing speed
	temp_compTime = ((double) this->getNumInstructions()
			/ (double) this->m_uint64MaxProcSpeedHz);

	//Figure out how many simulated scheduling intervals this
	//equates to
	this->m_uint64ComputationalTime = (temp_compTime
			* this->m_uint64MaxProcSpeedHz / g_Intervalusec);

	this->m_uint64DeadlineTime = this->getComputationalTime();
	//Add some random amount of time to the deadline
	int tempVal = rand() % 10;
	for (int i = 0; i < tempVal; i++) {
		this->m_uint64DeadlineTime += rand() % 1000;
	}
}

/**
 * 	getArrivalTime() Function:
 * 	Description:
 * 		This method returns the time the task was generated.
 *
 */
uint64_t ClTask::getArrivalTime() {
	return this->m_uint64ArrivalTime;
}

/**
 * 	getDeadline() Function:
 * 	Description:
 * 		This method returns the value that represents the time the task has to
 * 		complete.  For example, if arrival time is 1 and deadline is 6,
 * 		the actual deadline for the task is 7, however this function returns 6.
 * 		To get absolute deadline, use getAbsoluteDeadline();
 * 	Parameters:
 * 		N/A
 * 	Output:
 * 		uint64_t nanoSeconds
 * 			The number of nanoseconds representing the time from the system time recorded
 * 			when the task was generated.
 */
uint64_t ClTask::getDeadline() {
	return this->m_uint64DeadlineTime;
}

/**
 * 	getAbsoluteDeadline() Function:
 * 	Description:
 * 		This method returns the deadline time in clock ticks which the task must finish.
 * 	Parameters:
 * 		N/A
 * 	Output:
 * 		uint64_t Clock Time
 * 			The number of clock ticks representing the time from the system time recorded
 * 			when the task was generated.
 */
uint64_t ClTask::getAbsoluteDeadline() {
	return this->m_uint64ArrivalTime + this->m_uint64DeadlineTime;
}

/**
 * 	getComputationalTime Function:
 * 	Description:
 * 		This function computes the computational the current status of the
 * 		task.  This means, if the task has already executed some instructions
 * 		it adjust the computation time based on completed instructions, current
 * 		clock time, etc.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		uint64_t compTime
 * 			The number of estimated clock ticks that this task will take to complete
 * 			its task according to the number of instructions it has left.
 */
uint64_t ClTask::getComputationalTime() {
	double temp_compTime;
	int64_t temp_instructionsToCompute =
			this->m_uint64NumInstructions - this->m_uint64NumInstructionsCompleted;

	//If this is true, we've completed this task already.
	if(temp_instructionsToCompute < 0){
		return 0;
	}

	//Find out how many seconds it will take to execute this task
	//given a max processing speed and the number of instructions left
	temp_compTime = ((double) (temp_instructionsToCompute)
			/ (double) this->m_uint64MaxProcSpeedHz);

	//Figure out how many simulated scheduling intervals this
	//equates to.  Add one for any remaining instructions cut off
	//by the computation
	this->m_uint64ComputationalTime = (temp_compTime
			* this->m_uint64MaxProcSpeedHz / g_Intervalusec) + 1;

	return this->m_uint64ComputationalTime;
}

/**
 * 	getNumInstructions() Function:
 * 	Description:
 * 		This method returns the number of instructions that this tasks has.
 * 	Parameters:
 * 		N/A
 * 	Output:
 * 		uint64_t m_uint64NumInstructions
 * 			The number of instructions that is required for this task.  It is
 * 			guaranteed that the number of instructions and the task deadline
 * 			are possible to meet.
 */
uint64_t ClTask::getNumInstructions() {
	return this->m_uint64NumInstructions;
}

/**
 * 	getNumInstructionsCompleted() Function:
 * 	Description:
 * 		This method returns the number of instructions that have already
 * 		been processed during execution.  This is similar to a program counter.
 * 	Parameters:
 * 		N/A
 * 	Output:
 * 		uint64_t m_uint64NumInstructionsCompleted
 * 			The number of instructions thave have been successfully processed
 * 			on the running processor.
 */
uint64_t ClTask::getNumInstructionsCompleted() {
	return this->m_uint64NumInstructionsCompleted;
}

/**
 * 	getFinishedTimeNs() Function:
 * 	Description:
 * 		Get the finish time for the given task.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		uint64_t finishTime
 * 			The finish time based on clock ticks.
 */
uint64_t ClTask::getFinishTime() {
	return this->m_uint64FinishedTime;
}

/**
 * 	getAverageProcessedRateHz Function:
 * 	Description:
 * 		This function returns the average processed rate
 * 		which it had during runtime.  This does not reflect
 * 		the system average, just the task average.  This
 * 		was used by interested parties, but does not affect
 * 		the algorithm.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		uint64_t averageHz
 * 			The average processing rate for this given task
 * 			based on Hz.
 */
uint64_t ClTask::getAverageProcessedRateHz() {
	return this->m_uint64AverageProcessedRateHz;
}

/**
 * 	getSlackTime Function:
 * 	Description:
 * 		This function computes the available slack time
 * 		given the current time in clock ticks, the absolute
 * 		deadline and the computation time from current time.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		double slackTime
 * 			The slack time in a percentage.  If the value returned
 * 			is greater than or equal to 1, then this task is behind
 * 			or right at its deadline time.  If it returns less than
 * 			one then there is available overhead to use.
 */
double ClTask::getSlackTime() {
	uint64_t temp_currTime = 0;
	double temp_slackTime = 0;

	temp_currTime = ClRTClock::getInstance()->getTimeInterval();

	temp_slackTime =  (double) this->getComputationalTime()
			/ (double) (this->getAbsoluteDeadline() - temp_currTime);

	return temp_slackTime;
}

/**
 * 	setMaxProcSpeedHz Function:
 * 	Description:
 * 		This function sets the internal max processor sped for the
 * 		system in order to compute some values required.
 * 	Parameters:
 * 		uint64_t procSpeedInHz
 * 			The processor speed in Hz
 * 	Return:
 * 		void
 */
void ClTask::setMaxProcSpeedHz(uint64_t procSpeed) {
	this->m_uint64MaxProcSpeedHz = procSpeed;
}

/**
 * 	setArrivalTime Function:
 * 	Description:
 * 		This function record the clock time in ticks when this
 * 		task arrived at the system.
 * 	Parameters:
 * 		uint64_t arrival
 * 			Represents the clock time in ticks of the task arrival
 * 	Return:
 * 		void
 */
void ClTask::setArrivalTime(uint64_t arrival) {
	this->m_uint64ArrivalTime = arrival;
}

/**
 * 	setFinishedTime() Function:
 * 	Description:
 * 		Sets the time in which this task finished in clock ticks.
 * 	Parameters:
 * 		uint64_t finishedTime
 *			The finished time in clock ticks when this task finally finished.
 *	Return:
 *		void
 */
void ClTask::setFinishedTime(uint64_t finishedTime) {
	this->m_uint64FinishedTime = finishedTime;
}

/**
 * 	setProcessedRateHz Function:
 * 	Description:
 * 		This function is used to average the processed rate value
 * 		when this task is executed.  Each schedule interval should
 * 		add the processor rate at the end.
 * 	Parameters:
 * 		uint64_t procRate
 * 			The processor rate in hz
 * 	Return:
 * 		void
 */
void ClTask::setProcessedRateHz(uint64_t procRate) {
	this->m_uint64AverageProcessedRateHz
			= (this->m_uint64AverageProcessedRateHz + procRate) / 2;
}

/**
 * 	incrementCompletedInstructions Function:
 * 	Description:
 * 		This increments the number of instructions that were completed
 * 		this clock tick/schedule interval.
 * 	Parameters:
 * 		uint64_t numInstructions
 * 			The number of instructions that were completed this
 * 			schedule interval
 */
void ClTask::incrementCompletedInstructions(uint64_t numInstructions){
	this->m_uint64NumInstructionsCompleted += numInstructions;
}

/**
 * 	printTaskInternals Function:
 * 	Description:
 * 		Used for testing the ClTask functionality.  This is an internal
 * 		function, not to be used outside testing.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClTask::printTaskInternals() {
	cout << "Arrival time: " << this->getArrivalTime() << endl;
	cout << "Finished time: " << this->getFinishTime() << endl;
	cout << "Deadline time: " << this->getDeadline() << endl;
	cout << "Absolute Deadline time: " << this->getAbsoluteDeadline() << endl;
	cout << "Computational time: " << this->getComputationalTime() << endl;
	cout << "Number of Instructions: " << this->getNumInstructions() << endl;
	cout << "Max Processor Spd: " << this->m_uint64MaxProcSpeedHz << endl;
	cout << "Average processed spd: " << this->getAverageProcessedRateHz()
			<< endl;
	cout << "Slack time: " << this->getSlackTime() << endl;
	cout << "Met deadline? ";
	if (this->metDeadline()) {
		cout << "True" << endl;
	} else {
		cout << "False" << endl;
	}
}

/**
 * 	metDeadline Function:
 * 	Description:
 * 		This function compares the absolute deadline time with the
 * 		time finished value to see if the task was completed before
 * 		the deadline required.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		bool
 * 			Represents whether or not the task completed prior to
 * 			the deadline time.
 */
bool ClTask::metDeadline() {
	//No tasks can be computed at timestep 0
	if(this->getFinishTime() == 0){
		return false;
	}

	int64_t temp_diff = this->getAbsoluteDeadline() - this->getFinishTime();

	//deadline should be greater than finishTime in hard
	//real-time systems.
	if (temp_diff < 0) {
		return false;
	}

	return true;
}
